using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Gko.Utils;

namespace Gko.Video.Extensions
{
	[Serializable]
	public class Resolution : IEquatable<Resolution>
	{
		/// <summary>
		/// 320x200
		/// </summary>
		public static readonly Resolution CGA = new Resolution(320, 200);
		/// <summary>
		/// 1280x854
		/// </summary>
		public static readonly Resolution Custom1280x854 = new Resolution(1280, 854);
		/// <summary>
		/// 2048x1080
		/// </summary>
		public static readonly Resolution Custom2K = new Resolution(2048, 1080);
		/// <summary>
		/// 640x350
		/// </summary>
		public static readonly Resolution EGA = new Resolution(640, 350);
		/// <summary>
		/// 1920x1080
		/// </summary>
		public static readonly Resolution HD1080 = new Resolution(1920, 1080);
		/// <summary>
		/// 1280x720
		/// </summary>
		public static readonly Resolution HD720 = new Resolution(1280, 720);
		/// <summary>
		/// 720x384
		/// </summary>
		public static readonly Resolution Hercules = new Resolution(720, 348);
		/// <summary>
		/// 240x160
		/// </summary>
		public static readonly Resolution HQVGA = new Resolution(240, 160);
		/// <summary>
		/// 480x320
		/// </summary>
		public static readonly Resolution HVGA = new Resolution(480, 320);
		/// <summary>
		/// 640x240
		/// </summary>
		public static readonly Resolution HVGAWide = new Resolution(640, 240);
		/// <summary>
		/// 720x350
		/// </summary>
		public static readonly Resolution MDA = new Resolution(720, 350);
		/// <summary>
		/// 720x480
		/// </summary>
		public static readonly Resolution NTSC = new Resolution(720, 480);
		/// <summary>
		/// 1440x960
		/// </summary>
		public static readonly Resolution NTSCx4 = new Resolution(1440, 960);
		/// <summary>
		/// 768x576
		/// </summary>
		public static readonly Resolution PAL = new Resolution(768, 576);
		/// <summary>
		/// 1152x768
		/// </summary>
		public static readonly Resolution PALx2 = new Resolution(1152, 768);
		/// <summary>
		/// 360x240
		/// </summary>
		public static readonly Resolution QNTSC = new Resolution(360, 240);
		/// <summary>
		/// 384x288
		/// </summary>
		public static readonly Resolution QPAL = new Resolution(384, 288);
		/// <summary>
		/// 160x120
		/// </summary>
		public static readonly Resolution QQVGA = new Resolution(160, 120);
		/// <summary>
		/// 2560x2048
		/// </summary>
		public static readonly Resolution QSXGA = new Resolution(2560, 2048);
		/// <summary>
		/// 320x240
		/// </summary>
		public static readonly Resolution QVGA = new Resolution(320, 240);
		/// <summary>
		/// 2048x1536
		/// </summary>
		public static readonly Resolution QXGA = new Resolution(2048, 1536);
		/// <summary>
		/// 800x600
		/// </summary>
		public static readonly Resolution SVGA = new Resolution(800, 600);
		/// <summary>
		/// 1280x1024
		/// </summary>
		public static readonly Resolution SXGA = new Resolution(1280, 1024);
		/// <summary>
		/// 1400x1050
		/// </summary>
		public static readonly Resolution SXGAPlus = new Resolution(1400, 1050);
		/// <summary>
		/// 1600x1200
		/// </summary>
		public static readonly Resolution UXGA = new Resolution(1600, 1200);
		/// <summary>
		/// 640x480
		/// </summary>
		public static readonly Resolution VGA = new Resolution(640, 480);
		/// <summary>
		/// 720x240
		/// </summary>
		public static readonly Resolution WNTSC = new Resolution(720, 240);
		/// <summary>
		/// 768x288
		/// </summary>
		public static readonly Resolution WPAL = new Resolution(768, 288);
		/// <summary>
		/// 480x272
		/// </summary>
		public static readonly Resolution WQVGA = new Resolution(480, 272);
		/// <summary>
		/// 2560x1600
		/// </summary>
		public static readonly Resolution WQXGA = new Resolution(2560, 1600);
		/// <summary>
		/// 1024x600
		/// </summary>
		public static readonly Resolution WSVGA = new Resolution(1024, 600);
		/// <summary>
		/// 1280x960
		/// </summary>
		public static readonly Resolution WSXGA = new Resolution(1280, 960);
		/// <summary>
		/// 1680x1050
		/// </summary>
		public static readonly Resolution WSXGAPlus = new Resolution(1680, 1050);
		/// <summary>
		/// 1920x1200
		/// </summary>
		public static readonly Resolution WUXGA = new Resolution(1920, 1200);
		/// <summary>
		/// 800x480
		/// </summary>
		public static readonly Resolution WVGA = new Resolution(800, 480);
		/// <summary>
		/// 848x480
		/// </summary>
		public static readonly Resolution WVGA2 = new Resolution(848, 480);
		/// <summary>
		/// 854x480
		/// </summary>
		public static readonly Resolution WVGA3 = new Resolution(854, 480);
		/// <summary>
		/// 1280x768
		/// </summary>
		public static readonly Resolution WXGA = new Resolution(1280, 768);
		/// <summary>
		/// 1280x800
		/// </summary>
		public static readonly Resolution WXGA2 = new Resolution(1280, 800);
		/// <summary>
		/// 1366x768
		/// </summary>
		public static readonly Resolution WXGA3 = new Resolution(1366, 768);
		/// <summary>
		/// 1280x960
		/// </summary>
		public static readonly Resolution WXGAPlus = new Resolution(1280, 960);
		/// <summary>
		/// 1024x768
		/// </summary>
		public static readonly Resolution XGA = new Resolution(1024, 768);
		/// <summary>
		/// 1152x864
		/// </summary>
		public static readonly Resolution XGAPlus = new Resolution(1152, 864);

		private static readonly Resolution[] standardValues = new[] {
			CGA, 
			PALx2, 
			Custom1280x854, 
			NTSCx4, 
			Custom2K, 
			EGA, 
			HD1080, 
			HD720, 
			Hercules, 
			HQVGA, 
			HVGA, 
			HVGAWide, 
			MDA, 
			NTSC, 
			PAL, 
			QNTSC, 
			QPAL, 
			QQVGA, 
			QSXGA, 
			QVGA, 
			QXGA, 
			SVGA, 
			SXGA, 
			SXGAPlus, 
			UXGA, 
			VGA, 
			WNTSC, 
			WPAL, 
			WQVGA, 
			WQXGA, 
			WSVGA, 
			WSXGA, 
			WSXGAPlus, 
			WUXGA, 
			WVGA, 
			WVGA2, 
			WVGA3, 
			WXGA, 
			WXGA2, 
			WXGA3, 
			WXGAPlus, 
			XGA, 
			XGAPlus,
		};

		public static IEnumerable<Resolution> StandardValues
		{
			get
			{
				return standardValues.ToArray();
			}
		}

		private readonly int height;
		private readonly AspectRatio ratio;
		private readonly int width;

		public Resolution(int width, int height)
		{
			this.ratio = AspectRatio.Create(width, height);
			this.width = width;
			this.height = height;
		}

		public AspectRatio AspectRatio
		{
			[DebuggerStepThrough]
			get
			{
				return this.ratio;
			}
		}

		public int Width
		{
			[DebuggerStepThrough]
			get
			{
				return this.width;
			}
		}

		public int Height
		{
			[DebuggerStepThrough]
			get
			{
				return this.height;
			}
		}

		public int PixelsCount
		{
			get
			{
				return this.width * this.height;
			}
		}

		public Resolution FitIn(AspectRatio aspectRatio)
		{
			if (aspectRatio.Ratio < this.AspectRatio.Ratio) {
				return new Resolution((int)Math.Floor(this.height * aspectRatio.Ratio), this.height);
			}
			return new Resolution(this.width, (int)Math.Floor(this.width / aspectRatio.Ratio));
		}

		public Resolution FinInNearestStandard()
		{
			return this.FitIn(this.AspectRatio.NearestStandardRatio);
		}

		public Resolution ExtendTo(AspectRatio aspectRatio)
		{
			if (aspectRatio.Ratio > this.AspectRatio.Ratio) {
				return new Resolution((int)Math.Floor(this.height * aspectRatio.Ratio), this.height);
			}
			return new Resolution(this.width, (int)Math.Floor(this.width / aspectRatio.Ratio));
		}

		public Resolution ExtendToNearestStandard()
		{
			return this.ExtendTo(this.AspectRatio.NearestStandardRatio);
		}

		public override string ToString()
		{
			return "{0}x{1} [{2}]".Format(this.width, this.height, this.ratio);
		}

		public bool Equals(Resolution obj)
		{
			if (ReferenceEquals(null, obj)) {
				return false;
			}
			if (ReferenceEquals(this, obj)) {
				return true;
			}
			return obj.height == this.height && obj.width == this.width;
		}

		public override bool Equals(object obj)
		{
			if (ReferenceEquals(null, obj)) {
				return false;
			}
			if (ReferenceEquals(this, obj)) {
				return true;
			}
			if (obj.GetType() != typeof(Resolution)) {
				return false;
			}
			return Equals((Resolution)obj);
		}

		public override int GetHashCode()
		{
			unchecked {
				return (this.height * 397) ^ this.width;
			}
		}
	}
}